﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;

namespace ZhiHeng.Consume.ServiceLib.DAL
{
    public class Repository<T> : BaseRepository, IRepository
    {

        #region Base Implementation

        private bool _disposed;
        //Here we pass the connection and we flag the contextReused
        //so we can use the repository with the using clause ...
        public Repository()
        {
            this._contextReused = false;
        }

        #endregion

        #region Disposable

        //Dispose implementation
        public void Dispose()
        {
            DisposeObject(true);
            GC.SuppressFinalize(this);
        }

        //Distructor
        ~Repository()
        {
            DisposeObject(false);
        }

        //Concrete private implementation of the dispose method
        private void DisposeObject(bool disposing)
        {
            if (_disposed)
            {
                return;
            }
            if (disposing)
            {
                if (_context != null)
                {
                    _context.Dispose();
                }
                _disposed = true;
            }
        }

        #endregion


        public int Add(EntityObject entity)
        {
            var context = GetObjectContext();
            context.AddObject(entity.GetType().Name, entity);
            int result = context.SaveChanges();
            ReleaseObjectContextIfNotReused();
            return result;
        }

        public long Count()
        {
            var context = GetObjectContext();
            var query = new ObjectQuery<T>(
                typeof(T).Name,
                context,
                MergeOption.NoTracking);
            int count = query.Count();
            ReleaseObjectContextIfNotReused();
            return count;
        }

        public long Count(string predicate, params ObjectParameter[] parameters)
        {
            var context = GetObjectContext();
            var query = new ObjectQuery<T>(
                typeof(T).Name,
                context,
                MergeOption.NoTracking)
                .Where(predicate, parameters);
            int count = query.Count();
            ReleaseObjectContextIfNotReused();
            return count;
        }

        public int Delete(EntityObject entity)
        {
            var context = GetObjectContext();
            object originalItem;
            EntityKey key = context.CreateEntityKey(entity.GetType().Name, entity);
            if (context.TryGetObjectByKey(key, out originalItem))
            {
                context.DeleteObject(originalItem);
            }
            int result = context.SaveChanges();
            ReleaseObjectContextIfNotReused();
            return result;
        }

        public object GetAll()
        {
            var context = GetObjectContext();
            IList<T> list = context
                .CreateQuery<T>(
                    "[" + typeof(T).Name + "]")
                .ToList();
            ReleaseObjectContextIfNotReused();
            return list;
        }

        public object GetAll(string predicate, params ObjectParameter[] parameters)
        {
            var context = GetObjectContext();
            IList<T> list = context
                .CreateQuery<T>(
                    "[" + typeof(T).Name + "]")
                .Where(predicate, parameters)
                .ToList();
            ReleaseObjectContextIfNotReused();
            return list;
        }

        public object GetSingle(string predicate, params ObjectParameter[] parameters)
        {
            var tabName = typeof(T).Name;
            var context = GetObjectContext();
            var result = context
                .CreateQuery<T>(
                    "[" + tabName + "]")
                .Where(predicate, parameters).ToList();

            //.FirstOrDefault();
            ReleaseObjectContextIfNotReused();
            return result.FirstOrDefault();
        }

        public int Update(EntityObject entity)
        {
            var context = GetObjectContext();
            context.AttachTo(entity.GetType().Name, entity);
            context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
            int result = context.SaveChanges();
            ReleaseObjectContextIfNotReused();
            return result;
        }
    }
}
